package algocity.modelo.zona;

import algocity.modelo.energia.EnergiaInsuficienteException;
import algocity.modelo.juego.ColeccionesAlgoCity;
import algocity.modelo.juego.DineroInsuficienteException;
import algocity.modelo.juego.Monetizable;
import algocity.modelo.juego.MonetizableNull;
import algocity.modelo.mapa.Construible;
import algocity.modelo.mapa.Loteable;
import algocity.modelo.necesidades.*;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;


public abstract class Zona
        extends Construccion
        implements Serializable {

	protected Collection<Superficie> superficiesPermitidas = new ArrayList<Superficie>();
    protected Collection<Conexion> necesidades = new ArrayList<Conexion>();
    int consumoElectrico;
    protected Monetizable monedero;
    private Construible hectarea;

    public Zona( ){
		super();
		necesidades.add(new LineaDeTension(MonetizableNull.getInstance()));
		necesidades.add(new RutaPavimentada(MonetizableNull.getInstance()));
	}

    public int getConsumoElectrico (){
        return this.consumoElectrico;
    }

    public Construible getHectarea()
    {
        return hectarea;
    }

    private void verificarSuperficie (Loteable hectarea) throws  SuperficieInvalidaException {
		
		boolean permitirConstruccion = superficiesPermitidas.contains(hectarea.getSuperficie());
		if ( ! permitirConstruccion ){
			throw new SuperficieInvalidaException(hectarea.getSuperficie());
		}

	}

	public void construite (Construible hectarea) throws SuperficieInvalidaException, DineroInsuficienteException {
        verificarSuperficie(hectarea);
        try {
            monedero.quitarDinero(getCosto());
        } catch (DineroInsuficienteException e) {
            hectarea.compensarEnergia(getCosto());
            throw e;
        }

        try
        {
            hectarea.extraerEnergia(consumoElectrico);
        } catch (EnergiaInsuficienteException e)
        {
            hectarea.registrarAvisoEnergizacion( new AvisadorEnergizacion(this) );
        }

        hectarea.setConstruccion(this);
        ubicacion = hectarea.getPosicion();
        this.hectarea = hectarea;
    };

    /**
     * Verifica las condiciones de usabilidad del punto de vista de una construcción.
     * @return
     */
    public boolean esUsable() {
        return hectarea.estaEnergizada() && tieneRutaPavimentada();
    }

    private boolean tieneRutaPavimentada() {
        return tieneFacilidad(new RutaPavimentada(MonetizableNull.getInstance()));
    }

    private boolean tieneFacilidad(Conexion facilidad) {
        return ColeccionesAlgoCity.contiene( hectarea.getConexionesDisponibles(),
                                            new ComparadorNecesidad(facilidad) );
    }


    public boolean equals(Object otroObjeto)
    {
        if (!(otroObjeto instanceof Ruptura))
        {
            return super.equals(otroObjeto);
        }

        if (otroObjeto == this)
        {
            return true;
        }

        Zona otro = (Zona) otroObjeto;

        return superficiesPermitidas.equals(otro.superficiesPermitidas) &&
                necesidades.equals(otro.necesidades) &&
                ( consumoElectrico == otro.consumoElectrico) &&
                monedero.getDinero() == otro.monedero.getDinero() &&
                /**
                 *     FIXME StackOverflow
                 *     Debería poder usarse equals pero como el jugador tiene un mapa y este hectáreas y este
                 *     contrucciones se termina haciendo un stack overflow. En nuestro caso sólo debería compararse
                 *     el Monetizable que no está bien hacerlo acá pero se debe arreglar (issue #19)
                 */
                hectarea.getPosicion().equals(otro.hectarea.getPosicion()) && // no puedo comparar hectáreas porque da StackOverflow
                super.equals(otro);

    }

}
